package com.ly.heart.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.ly.common.PageParam;
import com.ly.common.core.domain.AjaxResult;
import com.ly.common.exception.CustomException;
import com.ly.common.utils.DateUtils;
import com.ly.common.utils.SecurityUtils;
import com.ly.common.utils.StringUtils;
import com.ly.common.utils.erp.*;
import com.ly.heart.domain.*;
import com.ly.heart.domain.dto.KingInvoiceReceivableDto;
import com.ly.heart.domain.dto.StartProcessDto;
import com.ly.common.core.domain.ActCurrentTaskVo;
import com.ly.heart.domain.vo.KingInvoiceReceivableMenuVo;
import com.ly.heart.domain.vo.KingInvoiceReceivableVo;
import com.ly.heart.mapper.KingInventoryMaterialMapper;
import com.ly.heart.mapper.KingInvoiceReceivableMapper;
import com.ly.heart.service.*;
import com.ly.heart.service.king.ReceivablePushService;
import com.ly.heart.util.ChineseToPinyin;
import com.ly.heart.util.CurrentUserUtil;
import com.ly.system.service.ISysDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

/**
 * 金蝶-发票-应收单/销售开票Service业务层处理
 * @author wutao
 * @date 2024-06-26
 */
@Service
@Slf4j
public class KingInvoiceReceivableServiceImpl extends ServiceImpl<KingInvoiceReceivableMapper, KingInvoiceReceivableEntity> implements IKingInvoiceReceivableService {

    @Resource
    private KingInvoiceReceivableMapper kingInvoiceReceivableEntityMapper;
    @Resource
    private IKingInvoiceReceivableDetailService iKingInvoiceReceivableDetailService;
    @Resource
    private IKingInvoiceReceivableReceiptPlanService iKingInvoiceReceivableReceiptPlanService;
    @Resource
    private IMaterialDetailService iMaterialDetailService;
    @Resource
    private KingInventoryMaterialMapper kingInventoryMaterialMapper;
    @Resource
    private IKingInventoryMaterialService iKingInventoryMaterialService;
    @Resource
    private IKingSaleRefundDetailService iKingSaleRefundDetailService;
    @Resource
    private IKingSaleRefundService iKingSaleRefundService;
    @Resource
    private IActModelService iActModelService;
    @Resource
    private IKingInventoryMaterialDetailService iKingInventoryMaterialDetailService;
    @Resource
    private IKingInventoryService iKingInventoryService;
    @Resource
    private IActTaskCommentService iActTaskCommentService;
    @Resource
    private ISaleOrderService iSaleOrderService;
    @Resource
    private ReceivablePushService receivablePushService;
    @Resource
    private IKingBaseCurrencyService iKingBaseCurrencyService;
    @Resource
    private ISysDeptService iSysDeptService;
    @Resource
    private IKingBaseSettlementTypeService iKingBaseSettlementTypeService;


    /**
     * 查询金蝶-发票-应收单/销售开票
     * @param id 金蝶-发票-应收单/销售开票ID
     * @return 金蝶-发票-应收单/销售开票
     */
    @Override
    public KingInvoiceReceivableVo selectKingInvoiceReceivableEntityById ( String id ) {
        KingInvoiceReceivableVo vo = new KingInvoiceReceivableVo ();
        //查询应收单基本信息
        KingInvoiceReceivableEntity receivableEntity = kingInvoiceReceivableEntityMapper.selectKingInvoiceReceivableEntityById ( id );
        //查询应收单明细
        KingInvoiceReceivableDetailEntity detailEntity = new KingInvoiceReceivableDetailEntity ();
        detailEntity.setInvoiceReceivableId ( id );
        List<KingInvoiceReceivableDetailEntity> receivableDetailEntities = iKingInvoiceReceivableDetailService.selectKingInvoiceReceivableDetailEntityList ( detailEntity );
        //查询收款计划
        List<KingInvoiceReceivableReceiptPlanEntity> receivableReceiptPlanEntities = iKingInvoiceReceivableReceiptPlanService.list ( new QueryWrapper<KingInvoiceReceivableReceiptPlanEntity> ().eq ( "invoice_receivable_id", id ) );
        vo.setKingInvoiceReceivableEntity ( receivableEntity ).setKingInvoiceReceivableDetailEntities ( receivableDetailEntities ).setKingInvoiceReceivableReceiptPlanEntities ( receivableReceiptPlanEntities );
        return vo;
    }

    /**
     * 查询金蝶-发票-应收单/销售开票列表
     * @param kingInvoiceReceivableEntity 金蝶-发票-应收单/销售开票
     * @return 金蝶-发票-应收单/销售开票
     */
    @Override
    public List<KingInvoiceReceivableEntity> selectKingInvoiceReceivableEntityList (KingInvoiceReceivableEntity kingInvoiceReceivableEntity) {
        kingInvoiceReceivableEntity.setIsUsed ( ConstUtil.IS_USED_YES );
        kingInvoiceReceivableEntity.setPage ( ( kingInvoiceReceivableEntity.getPage () - 1 ) * kingInvoiceReceivableEntity.getLimit () );
        List<KingInvoiceReceivableEntity> kingInvoiceReceivableEntities = kingInvoiceReceivableEntityMapper.selectKingInvoiceReceivableEntityList ( kingInvoiceReceivableEntity );
        List<String> ids = kingInvoiceReceivableEntities.stream ().map ( KingInvoiceReceivableEntity :: getId ).collect ( Collectors.toList () );
        if ( ! CollectionUtils.isEmpty ( ids ) ) {
            // 所有应收单的已核销金额
            //List<KingVerifyRecordsEntity> list = iKingVerifyRecordsService.list ( new LambdaQueryWrapper<KingVerifyRecordsEntity> ().
            //        in ( KingVerifyRecordsEntity :: getRelationId, ids ) );
            kingInvoiceReceivableEntities.forEach ( receivable -> {
                //查询对应源单单号
                //String sourceCode = getSourceCode ( receivable );
                //receivable.setSourceDocNo ( sourceCode );
                double sum = 0;//list.stream ().filter ( verify -> verify.getRelationId ().equals ( receivable.getId () ) ).mapToDouble ( verify -> Double.parseDouble ( verify.getVerifiedOwnAmount () ) ).sum ();
                if ( sum == 0 ) {
                    receivable.setVerifyStatus ( "未核销" );
                } else if ( sum > 0 && sum < Double.parseDouble ( receivable.getTotalTaxAmount () ) ) {
                    receivable.setVerifyStatus ( "部分核销" );
                } else {
                    receivable.setVerifyStatus ( "完全核销" );
                }
                // 对应源单金额
                if ( receivable.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_PAYABLE ) {
                    Optional<KingInvoiceReceivableEntity> first = kingInvoiceReceivableEntities.stream ().filter ( receivableDetail -> receivableDetail.getReceiptDetailId ().equals ( receivable.getReceiptDetailId () ) ).findFirst ();
                    if ( first.isPresent () ) {
                        String sourceAmount = calSourceAmount ( first.get () );
                        receivable.setSourceAmount ( CommonUtil.subStr ( "0", sourceAmount, 2 ) );
                    }
                } else {
                    String sourceAmount = calSourceAmount ( receivable );
                    receivable.setSourceAmount ( sourceAmount );
                }
                // 不含税差异金额，计算公式=（金额-对应源单金额）*汇率
                String costDifferenceAmount = CommonUtil.rideStr ( CommonUtil.subStr ( receivable.getNotTaxAmount (), receivable.getSourceAmount (), 2 ), receivable.getRate (), 2 );
                receivable.setCostDifferenceAmount ( costDifferenceAmount );
                // 对应源单价税合计
                if ( receivable.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_PAYABLE ) {
                    Optional<KingInvoiceReceivableEntity> first = kingInvoiceReceivableEntities.stream ().filter ( receivableDetail -> receivableDetail.getReceiptDetailId ().equals ( receivable.getReceiptDetailId () ) ).findFirst ();
                    if ( first.isPresent () ) {
                        String sourceTaxPriceAmount = calSourceTaxPriceAmount ( first.get () );
                        receivable.setSourceTaxPriceAmount ( sourceTaxPriceAmount );
                    }
                } else {
                    String sourceTaxPriceAmount = calSourceTaxPriceAmount ( receivable );
                    receivable.setSourceTaxPriceAmount ( sourceTaxPriceAmount );
                }
                // 价税合计差异金额，计算公式=（价税合计-对应源单价税合计）*汇率
                String diff = CommonUtil.rideStr ( CommonUtil.subStr ( receivable.getDetailTotalTaxPrice (), receivable.getSourceTaxPriceAmount (), 2 ), receivable.getRate (), 2 );
                receivable.setTaxPriceAmountDiff ( diff );
                // 对应源单汇率
                String sourceRate = calSourceRate ( receivable );
                receivable.setSourceRate ( sourceRate );
                // 成本汇率差异金额，计算公式=对应源单金额*（汇率-源单汇率）
                String rateDiff = CommonUtil.rideStr ( CommonUtil.subStr ( receivable.getRate (), receivable.getSourceRate (), 2 ), receivable.getSourceAmount (), 2 );
                receivable.setRateDiff ( rateDiff );
                // 价税合计汇率差异金额，计算公式=对应源单价税合计*（汇率-源单汇率）
                String taxPriceAmountRateDiff = CommonUtil.rideStr ( receivable.getSourceTaxPriceAmount (), CommonUtil.subStr ( receivable.getRate (), receivable.getSourceRate (), 2 ), 2 );
                receivable.setTaxPriceAmountRateDiff ( taxPriceAmountRateDiff );
                //处理最后一个审批人
                ActTaskCommentEntity actTaskCommentEntity = iActTaskCommentService.queryLastComment ( receivable.getInstanceId () );
                if ( actTaskCommentEntity != null ) {
                    receivable.setApprovedUser ( actTaskCommentEntity.getApprovedUser () );
                    receivable.setApprovedRemark ( actTaskCommentEntity.getRemark () );
                }
                //任务信息
                ActCurrentTaskVo currentTaskVo = iActModelService.getCurrentTaskByInstanceId ( receivable.getInstanceId () );
                Optional.ofNullable ( currentTaskVo ).ifPresent ( currentTask -> {
                    receivable.setCurrentTask ( currentTask );
                } );
            } );
        }
        return kingInvoiceReceivableEntities;
    }

    @Override
    public Integer selectKingInvoiceReceivableCount (KingInvoiceReceivableEntity kingInvoiceReceivableEntity) {
        Integer count = kingInvoiceReceivableEntityMapper.selectKingInvoiceReceivableCount ( kingInvoiceReceivableEntity );
        return count;
    }


    /**
     * 通过id查询关联数据
     * @param id
     * @return
     */
    @Override
    public KingInvoiceReceivableEntity querySingleById (String id) {
        KingInvoiceReceivableEntity kingInvoiceReceivableEntity = kingInvoiceReceivableEntityMapper.querySingleById ( id );
        return kingInvoiceReceivableEntity;
    }

    /**
     * 新增金蝶-发票-应收单/销售开票
     * 应收单来源：
     * 1、手动新增，无限制
     * 2、销售订单下推，下推的数量不能低于已出库+退货数量
     * 3、销售出库单下推，检查每个出库单的每个物料数量不得低于已生成应收单的数量
     * 4、销售退货单下推，
     * 5、冲红应收单下推
     * @param kingInvoiceReceivableDto 金蝶-发票-应收单/销售开票
     * @return 结果
     */
    @Override
    @Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AjaxResult draft (KingInvoiceReceivableDto kingInvoiceReceivableDto) {
        KingInvoiceReceivableEntity receivableEntity = kingInvoiceReceivableDto.getKingInvoiceReceivableEntity ();
        receivableEntity.setId ( SnowflakeIdWorker.getInstance ().nextStringId () );
        receivableEntity.setCreateUserId ( SecurityUtils.getLoginUser ().getUser ().getUserId () );
        receivableEntity.setCreateDate ( DateUtils.getNowDate () );
        //生成编码=单据类型汉字
        String py = ChineseToPinyin.getFirstLetter ( "销售开票" );
        int count = this.count ( new QueryWrapper<> () );
        String countStr = String.format ( "%08d", count );
        receivableEntity.setDocNo ( py.concat ( countStr ) );
        receivableEntity.setSettlementDeptId ( CurrentUserUtil.getCompanyId () );
        //1.手动新增，无限制
        List<KingInvoiceReceivableDetailEntity> kingInvoiceReceivableDetailEntities = kingInvoiceReceivableDto.getKingInvoiceReceivableDetailEntities ();
        //2.销售订单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_ORDER ) {
            checkSaleOrder ( kingInvoiceReceivableDetailEntities );
        }
        //3.销售出库单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_OUT_STORAGE ) {
            kingInvoiceReceivableDetailEntities = checkOutStorage ( kingInvoiceReceivableDetailEntities );
        }
        //4.销售退货单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_REFUND ) {
            refund ( kingInvoiceReceivableDetailEntities );
        }
        //5.冲红应收单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_PAYABLE ) {
            offset ( receivableEntity );
        }
        List<KingInvoiceReceivableDetailEntity> receivableDetailEntities = kingInvoiceReceivableDto.getKingInvoiceReceivableDetailEntities ();
        updateInvoiceDetail ( receivableDetailEntities, receivableEntity.getId (), receivableEntity.getRate () );
        List<KingInvoiceReceivableReceiptPlanEntity> receivableReceiptPlanEntities = kingInvoiceReceivableDto.getKingInvoiceReceivableReceiptPlanEntities ();
        int insertPlan = updateInvoiceReceiptPlan ( receivableReceiptPlanEntities, receivableEntity.getId () );
        if ( insertPlan == 0 ) {
            return AjaxResult.error ( "新增销售开票收款计划失败！" );
        }
        receivableEntity.setState ( ConstUtil.STATE_IN_DRAFT );
        boolean save = this.save ( receivableEntity );
        if ( ! save ) {
            throw new RuntimeException ( "暂存销售开票失败！" );
        }
        return AjaxResult.success ( "暂存销售开票成功", receivableEntity.getId () );
    }

    /**
     * 提交应收单
     * @param receivableEntity 金蝶-发票-应收单/销售开票
     * @return
     */
    @Override
    @Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AjaxResult submit (KingInvoiceReceivableEntity receivableEntity) {
        if ( StringUtils.isBlank ( receivableEntity.getId () ) ) {
            return AjaxResult.error ( "请先暂存该单据！" );
        }
        //处理审批流
        StartProcessDto startDto = new StartProcessDto ().
                setBusinessId ( receivableEntity.getId () ).
                setBusinessType ( receivableEntity.getBusinessType () ).setModelId ( receivableEntity.getModelId () ).
                setBusinessName ( "销售开票_".concat ( receivableEntity.getId () ) );
        String instanceId = iActModelService.startProcess ( startDto );
        receivableEntity.setInstanceId ( instanceId );
        receivableEntity.setState ( ConstUtil.STATE_IN_PROCESS );
        boolean save = this.update ( new LambdaUpdateWrapper<KingInvoiceReceivableEntity> ().
                set ( KingInvoiceReceivableEntity :: getInstanceId, instanceId ).
                set ( KingInvoiceReceivableEntity :: getState, ConstUtil.STATE_IN_PROCESS ).
                eq ( KingInvoiceReceivableEntity :: getId, receivableEntity.getId () ) );
        if ( ! save ) {
            throw new RuntimeException ( "提交销售开票失败！" );
        }
        return AjaxResult.success ( "提交销售开票成功" );
    }

    /**
     * 修改金蝶-发票-应收单/销售开票
     * @param kingInvoiceReceivableDto 金蝶-发票-应收单/销售开票
     * @return 结果
     */
    @Override
    @Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AjaxResult updateKingInvoiceReceivableEntity (KingInvoiceReceivableDto kingInvoiceReceivableDto) {
        KingInvoiceReceivableEntity receivableEntity = kingInvoiceReceivableDto.getKingInvoiceReceivableEntity ();
        receivableEntity.setUpdateUserId ( SecurityUtils.getLoginUser ().getUser ().getUserId () );
        receivableEntity.setUpdateDate ( DateUtils.getNowDate () );
        boolean b = this.updateById ( receivableEntity );
        if ( ! b ) {
            throw new CustomException ( "修改销售开票基本信息失败！" );
        }
        //1.手动新增，无限制
        List<KingInvoiceReceivableDetailEntity> kingInvoiceReceivableDetailEntities = kingInvoiceReceivableDto.getKingInvoiceReceivableDetailEntities ();
        //2.销售订单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_ORDER ) {
            checkSaleOrder ( kingInvoiceReceivableDetailEntities );
        }
        //3.销售出库单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_OUT_STORAGE ) {
            kingInvoiceReceivableDetailEntities = checkOutStorage ( kingInvoiceReceivableDetailEntities );
        }
        //4.销售退货单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_REFUND ) {
            refund ( kingInvoiceReceivableDetailEntities );
        }
        //5.冲红应收单下推
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_PAYABLE ) {
            offset ( receivableEntity );
        }
        updateInvoiceDetail ( kingInvoiceReceivableDetailEntities, receivableEntity.getId (), receivableEntity.getRate () );
        List<KingInvoiceReceivableReceiptPlanEntity> receivableReceiptPlanEntities = kingInvoiceReceivableDto.getKingInvoiceReceivableReceiptPlanEntities ();
        int insertPlan = updateInvoiceReceiptPlan ( receivableReceiptPlanEntities, receivableEntity.getId () );
        if ( insertPlan == 0 ) {
            return AjaxResult.error ( "新增销售开票收款计划失败！" );
        }
        return AjaxResult.success ();
    }

    /**
     * 批量删除金蝶-发票-应收单/销售开票
     * @param ids 需要删除的金蝶-发票-应收单/销售开票ID
     * @return 结果
     */
    @Override
    @Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AjaxResult deleteKingInvoiceReceivableEntityByIds (String[] ids) {
        KingInvoiceReceivableEntity receivableEntity = new KingInvoiceReceivableEntity ();
        for ( int i = 0; i < ids.length; i++ ) {
            receivableEntity.setId ( ids[i] );
            receivableEntity.setIsUsed ( ConstUtil.IS_USED_NO );
            int update = kingInvoiceReceivableEntityMapper.updateKingInvoiceReceivableEntity ( receivableEntity );
            if ( update == 0 ) {
                throw new CustomException ( "删除销售开票失败！" );
            }
        }
        LambdaUpdateWrapper<KingInvoiceReceivableDetailEntity> detailUpdate = new LambdaUpdateWrapper<> ();
        detailUpdate.set ( KingInvoiceReceivableDetailEntity :: getIsUsed, ConstUtil.IS_USED_NO ).in ( KingInvoiceReceivableDetailEntity :: getInvoiceReceivableId, ids );
        boolean updateDetail = iKingInvoiceReceivableDetailService.update ( detailUpdate );
        if ( ! updateDetail ) {
            throw new CustomException ( "删除销售开票失败！" );
        }
        return AjaxResult.success ( "删除销售开票成功" );
    }


    /**
     * 收款单选单，现在应收单，以应收单主表为主体
     * @param kingInvoiceReceivableEntity
     * @return
     */
    @Override
    public AjaxResult queryList ( KingInvoiceReceivableEntity kingInvoiceReceivableEntity ) {
        kingInvoiceReceivableEntity.setPage ( ( kingInvoiceReceivableEntity.getPage () - 1 ) * kingInvoiceReceivableEntity.getLimit () );
        List<KingInvoiceReceivableEntity> kingInvoiceReceivableEntities = kingInvoiceReceivableEntityMapper.queryList ( kingInvoiceReceivableEntity );
        Integer integer = kingInvoiceReceivableEntityMapper.queryCount ( kingInvoiceReceivableEntity );
        PageParam p = new PageParam ();
        p.setRecords ( kingInvoiceReceivableEntities ).setTotal ( integer );
        return AjaxResult.success ( p );
    }

    /**
     * 应收单冲红，选择应收单
     * @param kingInvoiceReceivableEntity
     * @return
     */
    @Override
    public AjaxResult queryListByReceivable (KingInvoiceReceivableEntity kingInvoiceReceivableEntity) {
        kingInvoiceReceivableEntity.setPage ( ( kingInvoiceReceivableEntity.getPage () - 1 ) * kingInvoiceReceivableEntity.getLimit () );
        List<KingInvoiceReceivableMenuVo> kingInvoiceReceivableEntities = kingInvoiceReceivableEntityMapper.queryListByReceivable ( kingInvoiceReceivableEntity );
        Integer integer = kingInvoiceReceivableEntityMapper.queryListByReceivableCount ( kingInvoiceReceivableEntity );
        PageParam p = new PageParam ();
        p.setRecords ( kingInvoiceReceivableEntities ).setTotal ( integer );
        return AjaxResult.success ( p );
    }

    /**
     * 应收单审核后业务处理
     * 1、如果是红冲，则怼掉源应付单的源出库单下推记录
     * 2、修改状态
     * 3、提交金蝶
     * @param id
     * @return
     */
    @Override
    @Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AjaxResult approve (String id) {
        KingInvoiceReceivableEntity receivableEntity = querySingleById ( id );
        if ( receivableEntity == null ) {
            throw new CustomException ( "该单据不存在！" );
        }
        //1.处理红冲
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_PAYABLE ) {
            List<KingInvoiceReceivableDetailEntity> list = iKingInvoiceReceivableDetailService.list ( new LambdaQueryWrapper<KingInvoiceReceivableDetailEntity> ().
                    eq ( KingInvoiceReceivableDetailEntity :: getInvoiceReceivableId, receivableEntity.getId () ) );
            List<String> sourcePayableDetailIds = list.stream ().map ( KingInvoiceReceivableDetailEntity :: getSourceMaterialDetailId ).collect ( Collectors.toList () );
            sourcePayableDetailIds.forEach ( sourceDetail -> {
                iKingInvoiceReceivableDetailService.update ( new LambdaUpdateWrapper<KingInvoiceReceivableDetailEntity> ().
                        set ( KingInvoiceReceivableDetailEntity :: getIsRelease, true ).eq ( KingInvoiceReceivableDetailEntity :: getId, sourceDetail ) );
            } );
        }
        boolean update = this.update ( new LambdaUpdateWrapper<KingInvoiceReceivableEntity> ().
                set ( KingInvoiceReceivableEntity :: getState, ConstUtil.STATE_FINISH ).
                eq ( KingInvoiceReceivableEntity :: getId, id ) );
        if ( ! update ) {
            throw new CustomException ( "修改审核完成状态失败！" );
        }
        log.info ( "id=>{} 修改审批流状态成功。", id );
        //receivablePushService.push ( id );
        return AjaxResult.success ("销售开票审核并推送金蝶成功");
    }

    /**
     * 出入库单审核后，检查有无上级销售/采购订单，如果有则检查该订单是否提前下推应收/应付单，如果已提前下推应收/应付
     * 则生成一正一负应付单，源单分别为出入库单以及订单
     * @param inventoryId：出库单Id
     * @param orderId：销售订单Id
     * @return
     */
    @Override
    public AjaxResult inventoryApprove (String inventoryId, String orderId) {
        KingInventoryEntity inventoryEntity = iKingInventoryService.getById ( inventoryId );
        if ( inventoryEntity == null ) {
            return AjaxResult.error ( "无此出库单" );
        }
        List<KingInvoiceReceivableDetailEntity> list = iKingInvoiceReceivableDetailService.list ( new LambdaQueryWrapper<KingInvoiceReceivableDetailEntity> ().
                eq ( KingInvoiceReceivableDetailEntity :: getSourceId, orderId ) );
        if ( list == null && list.size () <= 0 ) {
            return AjaxResult.error ( "未提前生成应收单" );
        }
        KingInvoiceReceivableDto dtoByInventory = new KingInvoiceReceivableDto ();
        List<KingInventoryMaterialEntity> inventoryMaterialEntities = iKingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().
                eq ( KingInventoryMaterialEntity :: getInventoryId, inventoryId ) );
        //生成源单为入库单的正应收单
        KingInvoiceReceivableEntity receivableEntityByInventory = new KingInvoiceReceivableEntity ();
        receivableEntityByInventory.setDocTypeCode ( KingConstUtil.KING_STAND_RECEIVABLE );
        receivableEntityByInventory.setBizTime ( DateUtils.getNowDate () );
        receivableEntityByInventory.setDueTime ( DateUtils.getNowDate () );
        receivableEntityByInventory.setCustomerId ( inventoryEntity.getCustomerId () );
        KingBaseCurrencyEntity one = iKingBaseCurrencyService.getOne ( new LambdaQueryWrapper<KingBaseCurrencyEntity> ().eq ( KingBaseCurrencyEntity :: getCode, inventoryEntity.getSettlementCurrency () ) );
        receivableEntityByInventory.setBaseCurrencyId ( one.getId () );
        receivableEntityByInventory.setTotalTaxAmount ( inventoryEntity.getTotalPriceTax () );
        receivableEntityByInventory.setSourceDocType ( 3 );
        receivableEntityByInventory.setRemarks ( "系统自动生产蓝冲红" );
        receivableEntityByInventory.setIsExtraPriceTax ( true );
        receivableEntityByInventory.setIsIncludeTaxPrice ( true );
        receivableEntityByInventory.setAccountType ( 2 );
        receivableEntityByInventory.setSettlementDeptId ( inventoryEntity.getSettlementOrg () );
        receivableEntityByInventory.setReceiptDeptId ( inventoryEntity.getSettlementOrg () );
        receivableEntityByInventory.setSaleCompanyId ( inventoryEntity.getPurchaseOrg () );
        receivableEntityByInventory.setOrderCustomerId ( inventoryEntity.getCustomerId () );
        receivableEntityByInventory.setReceivingCustomerId ( inventoryEntity.getCustomerId () );
        receivableEntityByInventory.setPayCustomerId ( inventoryEntity.getCustomerId () );
        receivableEntityByInventory.setSettlementTypeId ( inventoryEntity.getSettlementMethod () );
        receivableEntityByInventory.setDueCalDate ( DateUtils.getNowDate () );
        receivableEntityByInventory.setRate ( inventoryEntity.getExchangeRate () );
        receivableEntityByInventory.setRateAmount ( inventoryEntity.getTaxAmount () );
        receivableEntityByInventory.setRateAmountCurrency ( CommonUtil.rideStr ( inventoryEntity.getExchangeRate (), inventoryEntity.getTaxAmount (), 2 ) );
        receivableEntityByInventory.setTotalTaxPriceCurrency ( CommonUtil.rideStr ( inventoryEntity.getExchangeRate (), inventoryEntity.getTotalPriceTax (), 2 ) );
        receivableEntityByInventory.setNotTaxAmount ( inventoryEntity.getMoneyAmount () );
        receivableEntityByInventory.setNotTaxAmountCurrency ( CommonUtil.rideStr ( inventoryEntity.getExchangeRate (), inventoryEntity.getMoneyAmount (), 2 ) );
        List<KingInvoiceReceivableDetailEntity> receivableDetailEntitiesByInventory = new ArrayList<> ();
        inventoryMaterialEntities.forEach ( material -> {
            KingInvoiceReceivableDetailEntity receivableDetailEntity = new KingInvoiceReceivableDetailEntity ();
            receivableDetailEntity.setMaterialId ( material.getMaterialId () );
            receivableDetailEntity.setMaterialCode ( material.getMaterialCode () );
            receivableDetailEntity.setUnit ( material.getPricingUnit () );
            receivableDetailEntity.setPrice ( material.getPrice () );
            receivableDetailEntity.setNum ( material.getReceiptsNum () );
            receivableDetailEntity.setTaxPrice ( material.getBusinessTaxPrice () );
            receivableDetailEntity.setRate ( material.getTaxRate () );
            receivableDetailEntity.setTotalTaxPrice ( material.getTotalTaxPrice () );
            receivableDetailEntity.setNotTaxAmount ( material.getMoneyAmount () );
            receivableDetailEntity.setRateAmount ( material.getTaxAmount () );
            receivableDetailEntity.setIsFee ( material.getIsGiveaway () );
            receivableDetailEntity.setSaleOrderCode ( material.getRelationCode () );
            receivableDetailEntity.setSourceDocType ( 3 );//入库单
            receivableDetailEntity.setSourceId ( inventoryId );
            receivableDetailEntity.setSourceMaterialDetailId ( material.getId () );
            receivableDetailEntity.setRemarks ( "系统自动生产蓝冲红" );
            receivableDetailEntitiesByInventory.add ( receivableDetailEntity );
        } );
        dtoByInventory.setKingInvoiceReceivableEntity ( receivableEntityByInventory );
        dtoByInventory.setKingInvoiceReceivableDetailEntities ( receivableDetailEntitiesByInventory );
        this.draft ( dtoByInventory );
        //2.生乘负的（红冲）应收单，源单为销售订单
        KingInvoiceReceivableDto dtoByOrder = new KingInvoiceReceivableDto ();
        SaleOrderEntity saleOrderEntity = iSaleOrderService.getById ( orderId );
        if ( saleOrderEntity == null ) {
            return AjaxResult.error ( "无此销售订单" );
        }
        List<MaterialDetailEntity> materialDetailEntities = iMaterialDetailService.list ( new LambdaQueryWrapper<MaterialDetailEntity> ().
                eq ( MaterialDetailEntity :: getRelationId, orderId ).eq ( MaterialDetailEntity :: getType, ConstUtil.ORDER_SALE ) );
        KingInvoiceReceivableEntity receivableEntityByOrder = new KingInvoiceReceivableEntity ();
        receivableEntityByOrder.setDocTypeCode ( KingConstUtil.KING_STAND_RECEIVABLE );
        receivableEntityByOrder.setBizTime ( DateUtils.getNowDate () );
        receivableEntityByOrder.setDueTime ( DateUtils.getNowDate () );
        receivableEntityByOrder.setCustomerId ( saleOrderEntity.getCustomerId () );
        one = iKingBaseCurrencyService.getOne ( new LambdaQueryWrapper<KingBaseCurrencyEntity> ().eq ( KingBaseCurrencyEntity :: getCode, saleOrderEntity.getCurrency () ) );
        receivableEntityByOrder.setBaseCurrencyId ( one.getId () );
        receivableEntityByOrder.setTotalTaxAmount ( saleOrderEntity.getTotalTaxPrice () );
        receivableEntityByOrder.setSourceDocType ( 2 );
        receivableEntityByOrder.setRemarks ( "系统自动生成红冲单" );
        receivableEntityByOrder.setIsExtraPriceTax ( true );
        receivableEntityByOrder.setIsIncludeTaxPrice ( true );
        receivableEntityByOrder.setAccountType ( 2 );
        receivableEntityByOrder.setSettlementDeptId ( saleOrderEntity.getSaleOrg () ); //销售组织Id
        receivableEntityByOrder.setReceiptDeptId ( saleOrderEntity.getSaleOrg () );
        receivableEntityByOrder.setSaleCompanyId ( saleOrderEntity.getSaleOrg () );
        receivableEntityByOrder.setOrderCustomerId ( saleOrderEntity.getCustomerId () );
        receivableEntityByOrder.setReceivingCustomerId ( saleOrderEntity.getCustomerId () ); //收货方先用客户
        receivableEntityByOrder.setPayCustomerId ( saleOrderEntity.getCustomerId () );
        receivableEntityByOrder.setSettlementTypeId ( saleOrderEntity.getSettlementType () );
        receivableEntityByOrder.setDueCalDate ( DateUtils.getNowDate () );
        receivableEntityByOrder.setRate ( saleOrderEntity.getRate () );
        receivableEntityByOrder.setRateAmount ( saleOrderEntity.getTaxAmount () );
        receivableEntityByOrder.setRateAmountCurrency ( CommonUtil.rideStr ( saleOrderEntity.getRate (), saleOrderEntity.getTaxAmount (), 2 ) );
        receivableEntityByOrder.setTotalTaxPriceCurrency ( CommonUtil.rideStr ( saleOrderEntity.getRate (), saleOrderEntity.getTotalTaxPrice (), 2 ) );
        receivableEntityByOrder.setNotTaxAmount ( saleOrderEntity.getValueTax () );
        receivableEntityByOrder.setNotTaxAmountCurrency ( CommonUtil.rideStr ( saleOrderEntity.getRate (), saleOrderEntity.getValueTax (), 2 ) );
        List<KingInvoiceReceivableDetailEntity> receivableDetailEntitiesByOrder = new ArrayList<> ();
        materialDetailEntities.forEach ( detail -> {
            KingInvoiceReceivableDetailEntity receivableDetailEntity = new KingInvoiceReceivableDetailEntity ();
            receivableDetailEntity.setMaterialId ( detail.getMaterialId () );
            receivableDetailEntity.setMaterialCode ( detail.getMaterialCode () );
            receivableDetailEntity.setUnit ( detail.getPricingUnit () );
            receivableDetailEntity.setPrice ( detail.getPrice () );
            receivableDetailEntity.setNum ( detail.getNumber () );
            receivableDetailEntity.setTaxPrice ( detail.getBusinessTaxPrice () );
            receivableDetailEntity.setRate ( detail.getTaxRate () );
            receivableDetailEntity.setTotalTaxPrice ( detail.getTotalTaxPrice () );
            receivableDetailEntity.setNotTaxAmount ( detail.getNoTaxMoney () );
            receivableDetailEntity.setRateAmount ( detail.getTaxAmount () );
            receivableDetailEntity.setIsFee ( detail.getIsGiveaway () );
            receivableDetailEntity.setSourceDocType ( 2 );//入库单
            receivableDetailEntity.setSourceId ( orderId );
            receivableDetailEntity.setSourceMaterialDetailId ( detail.getId () );
            receivableDetailEntity.setRemarks ( "系统自动生成红冲单" );
            receivableDetailEntitiesByOrder.add ( receivableDetailEntity );
        } );
        dtoByOrder.setKingInvoiceReceivableEntity ( receivableEntityByOrder );
        dtoByOrder.setKingInvoiceReceivableDetailEntities ( receivableDetailEntitiesByOrder );
        this.draft ( dtoByOrder );
        return AjaxResult.success ( "出库单审核后自动生成应收单成功" );
    }

    /**
     * 销售订单下推应收单，校验：
     * 1、销售订单下推属于提前开票，必须确保有提前开票的数量
     * 2、剩余可提前开票的数量=剩余出库的数量-已提前开票的数量
     * 3、剩余出库的数量=销售订单总数-已出库数量-累计退货补货的数量(意味着换货流程还未走完)
     * 4、已提前开票=应收单列表统计源单类型是销售订单的开票记录
     * 故：剩余可提前开票的数量=剩余出库的数量(销售订单总数-已出库数量-累计退货补货的数量(意味着换货流程还未走完))-已提前开票的数量(应收单列表统计源单类型是销售订单的开票记录)
     * @param receivableDetailEntities
     */
    private void checkSaleOrder (List<KingInvoiceReceivableDetailEntity> receivableDetailEntities) {
        if ( CollectionUtils.isEmpty ( receivableDetailEntities ) ) {
            return;
        }
        receivableDetailEntities = receivableDetailEntities.stream ().filter ( detail -> StringUtils.isNotBlank ( detail.getSourceMaterialDetailId () ) ).collect ( Collectors.toList () );
        //销售订单Ids
        List<String> ids = receivableDetailEntities.stream ().map ( KingInvoiceReceivableDetailEntity :: getSourceId ).collect ( Collectors.toList () );
        //所有销售订单的每个物料列表
        List<MaterialDetailEntity> materialDetailListBySaleOrder = iMaterialDetailService.list ( new LambdaQueryWrapper<MaterialDetailEntity> ().
                eq ( MaterialDetailEntity :: getType, ConstUtil.ORDER_SALE ).in ( MaterialDetailEntity :: getRelationId, ids ) );
        log.info ( "已生成销售订单的物料列表：materialDetailListBySaleOrder->{}", materialDetailListBySaleOrder );
        //检查每个物料数量减去已出库数量加上已退货的数量
        for ( int i = 0; i < materialDetailListBySaleOrder.size (); i++ ) {
            for ( int j = 0; j < receivableDetailEntities.size (); j++ ) {
                // 同一个物料
                if ( materialDetailListBySaleOrder.get ( i ).getId ().equals ( receivableDetailEntities.get ( j ).getId () ) ) {
                    //页面新增应收单的物料数量
                    double num = Double.parseDouble ( receivableDetailEntities.get ( j ).getNum () );
                    //销售订单中物料数量
                    double numByOrder = Double.parseDouble ( materialDetailListBySaleOrder.get ( i ).getNumber () );
                    //已出库物料数量
                    List<KingInventoryMaterialEntity> inventoryMaterialEntities = kingInventoryMaterialMapper.selectList ( new QueryWrapper<KingInventoryMaterialEntity> ().
                            eq ( "relation_id", materialDetailListBySaleOrder.get ( i ).getRelationId () ).
                            eq ( "material_id", materialDetailListBySaleOrder.get ( i ).getId () ) );
                    double numByOut = inventoryMaterialEntities.stream ().mapToDouble ( inventoryMaterial -> Double.parseDouble ( inventoryMaterial.getReceiptsNum () ) ).sum ();
                    //累计退货补货的数量
                    KingSaleRefundDetailEntity saleRefundDetailEntity = new KingSaleRefundDetailEntity ();
                    saleRefundDetailEntity.setRefundType ( String.valueOf ( KingConstUtil.SALE_REFUND_TYPE_REFUND ) ).setSaleOrderId ( materialDetailListBySaleOrder.get ( i ).getRelationId () ).setMaterialId ( materialDetailListBySaleOrder.get ( i ).getId () );
                    List<KingSaleRefundDetailEntity> kingSaleRefundDetailEntities = iKingSaleRefundDetailService.queryRelationList ( saleRefundDetailEntity );
                    double numByRefund = kingSaleRefundDetailEntities.stream ().mapToDouble ( x -> Double.parseDouble ( x.getRefundNum () ) ).sum ();
                    //已提前开票的数量
                    int numByReceivable = iKingInvoiceReceivableDetailService.count ( new QueryWrapper<KingInvoiceReceivableDetailEntity> ().
                            eq ( "material_id", materialDetailListBySaleOrder.get ( i ).getId () ).
                            eq ( "sale_order_id", materialDetailListBySaleOrder.get ( i ).getRelationId () ).
                            eq ( "is_used", ConstUtil.IS_USED_YES ) );
                    if ( num > ( numByOrder - numByOut - numByRefund - numByReceivable ) ) {
                        throw new RuntimeException ( "销售订单下推应收单时，第【" + receivableDetailEntities.get (j).getLineNumber () + "】分录行数量超限！" );
                    }
                }
            }
        }
    }

    /**
     * 销售出库单下推应收单，要求同一个客户、同一收货组织、同一销售员
     * 最大可推数量=剩余应收(未开票)数量
     * 剩余应收(未开票)数量=出库数量-累计应收(开票)数量
     * 故：最大可推数量=出库数量-累计应收(开票)数量
     * @param receivableDetailEntities：页面新增应收单明细列表
     */
    private List<KingInvoiceReceivableDetailEntity> checkOutStorage (List<KingInvoiceReceivableDetailEntity> receivableDetailEntities) {
        receivableDetailEntities = receivableDetailEntities.stream ().filter ( detail -> StringUtils.isNotBlank ( detail.getSourceId () ) ).collect( Collectors.toList());
        //出库单Ids
        List<String> ids = receivableDetailEntities.stream ().map ( KingInvoiceReceivableDetailEntity :: getSourceId ).collect ( Collectors.toList () );
        //通过出入库单Id查询出入库明细列表
        List<KingInventoryMaterialEntity> list = iKingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().
                eq ( KingInventoryMaterialEntity :: getId, ids ) );
        log.info ( "已出库的物料明细列表：materialDetailByOut->{}", list );
        receivableDetailEntities.forEach ( receivableDetail -> {
            //新增界面的物料数量
            double addNum = StringUtils.isBlank ( receivableDetail.getNum () ) ? 0.0 : Double.parseDouble ( receivableDetail.getNum () );
            //已下推物料数量
            double executeSum = 0;
            KingInvoiceReceivableDetailEntity one = iKingInvoiceReceivableDetailService.getOne ( new LambdaQueryWrapper<KingInvoiceReceivableDetailEntity> ().
                    eq ( KingInvoiceReceivableDetailEntity :: getSourceMaterialDetailId, receivableDetail.getSourceMaterialDetailId () ).
                    eq ( KingInvoiceReceivableDetailEntity :: getIsUsed, ConstUtil.IS_USED_YES ) );
            if ( one != null ) {
                executeSum = Double.parseDouble ( one.getNum () );
            }
            //已出库物料总数量
            double totalNum = list.stream ().filter ( material -> material.getId ().equals ( receivableDetail.getSourceMaterialDetailId () ) ).mapToDouble ( material -> Double.parseDouble ( material.getReceiptsNum () ) ).sum ();
            if ( addNum > ( totalNum - executeSum ) ) {
                throw new RuntimeException ( "通过销售出库单下推应收单，物料数量超限！" );
            }
            //平账
            if ( addNum == ( totalNum - executeSum ) ) {
                // 拿到出库单明细行的金额信息
                KingInventoryMaterialEntity inventoryMaterialEntity = iKingInventoryMaterialService.getOne ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().
                        eq ( KingInventoryMaterialEntity :: getId, receivableDetail.getSourceMaterialDetailId () ) );
                String totalTaxPrice = inventoryMaterialEntity.getTotalTaxPrice ();// 价税合计
                String price = inventoryMaterialEntity.getPrice (); // 单价
                String amountMoney = inventoryMaterialEntity.getMoneyAmount ();//不含税金额
                receivableDetail.setTotalTaxPrice ( totalTaxPrice );//平价税合计
                receivableDetail.setPrice ( price );//平含税单价
                receivableDetail.setNotTaxAmount ( amountMoney );
            }
        } );
        return receivableDetailEntities;
    }

    /**
     * 销售退货单下推应收单，校验：
     * 1、最大可推数量=下推的退货单里面的物料数量
     * @param invoiceReceivableDetailEntities：明细
     */
    private void refund (List<KingInvoiceReceivableDetailEntity> invoiceReceivableDetailEntities) {
        //销售退货单Ids
        List<String> ids = invoiceReceivableDetailEntities.stream ().map ( KingInvoiceReceivableDetailEntity :: getSourceId ).collect ( Collectors.toList () );
        List<KingSaleRefundDetailEntity> saleRefundDetailEntities = iKingSaleRefundDetailService.list ( new QueryWrapper<KingSaleRefundDetailEntity> ().in ( "sale_refund_id", ids ) );
        for ( int i = 0; i < saleRefundDetailEntities.size (); i++ ) {
            for ( int j = 0; j < invoiceReceivableDetailEntities.size (); j++ ) {
                double num = Double.parseDouble ( invoiceReceivableDetailEntities.get ( j ).getNum () );
                if ( Math.abs ( num ) > Math.abs ( Double.parseDouble ( saleRefundDetailEntities.get ( i ).getRefundNum () ) ) ) {
                    throw new CustomException ( "通过销售退货单下推应付单，第【" + invoiceReceivableDetailEntities.get ( j ).getLineNumber () + "】分录行数量超限！" );
                }
            }
        }
    }

    /**
     * 应收单红冲
     * 源应收单开错，开一张金额为负值相等的红字应收单，进行红冲
     * @param kingInvoiceReceivableEntity
     */
    private void offset (KingInvoiceReceivableEntity kingInvoiceReceivableEntity) {
        if ( StringUtils.isBlank ( kingInvoiceReceivableEntity.getParentId () ) ) {
            throw new CustomException ( "所选单据对象为空" );
        }
        KingInvoiceReceivableEntity parentEntity = this.getById ( kingInvoiceReceivableEntity.getParentId () );
        if ( parentEntity == null ) {
            throw new CustomException ( "所选单据不存在" );
        }
        double sum = Double.sum ( Double.parseDouble ( parentEntity.getTotalTaxAmount () ), Double.parseDouble ( kingInvoiceReceivableEntity.getTotalTaxAmount () ) );
        if ( sum != 0 ) {
            throw new CustomException ( "冲红单据的金额必须为负数，面值必须等于源单据" );
        }
        if ( ! parentEntity.getSaleUserId ().equals ( kingInvoiceReceivableEntity.getSaleUserId () ) ) {
            throw new CustomException ( "冲红单据的销售员必须与源单据销售员保持一致" );
        }
        if ( ! parentEntity.getCustomerId ().equals ( kingInvoiceReceivableEntity.getCustomerId () ) ) {
            throw new CustomException ( "冲红单据的客户必须与源单据客户保持一致" );
        }
        //符合冲红，释放源父应收单与上级单据的关系（销售订单/销售出库单），让上级单据后续可以再次下推
        log.info ( "父应收单【{}】！", parentEntity.getDocNo () );
        //更新父应收单状态为冲红
        //boolean update = this.update ( new UpdateWrapper<KingInvoiceReceivableEntity> ().
        //        set ( "status", KingConstUtil.KING_DATA_EXAMINE_STATUS_OFFSET ).
        //        set ( "change_time", DateUtils.getNowDate () ).
        //        eq ( "id", parentEntity.getId () ) );
        //if ( ! update ) {
        //    throw new RuntimeException ( "修改父应收单【" + parentEntity.getDocNo () + "】冲红失败" );
        //}
        //撤回明细记录
        //boolean updateDetail = iKingInvoiceReceivableDetailService.update ( new UpdateWrapper<KingInvoiceReceivableDetailEntity> ().
        //        set ( "change_time", DateUtils.getNowDate () ).
        //        set ( "is_used", ConstUtil.IS_USED_NO ).
        //        eq ( "invoice_payable_id", parentEntity.getId () ) );
        //if ( ! updateDetail ) {
        //    throw new RuntimeException ( "更新应收明细作废" );
        //}
    }

    /**
     * 更新应收单/销售开票里的明细
     * @param kingInvoiceReceivableDetailEntities
     * @param receivableId
     * @return
     */
    private void updateInvoiceDetail ( List<KingInvoiceReceivableDetailEntity> kingInvoiceReceivableDetailEntities, String receivableId, String rate ) {
        if ( ! CollectionUtils.isEmpty ( kingInvoiceReceivableDetailEntities ) ) {
            String batchNumber = BatchNumberGenerator.generateBatchNumber ();
            iKingInvoiceReceivableDetailService.remove ( new LambdaUpdateWrapper<KingInvoiceReceivableDetailEntity> ().eq ( KingInvoiceReceivableDetailEntity :: getInvoiceReceivableId, receivableId ) );
            kingInvoiceReceivableDetailEntities.forEach ( kingInvoiceReceivableDetailEntity -> {
                kingInvoiceReceivableDetailEntity.setInvoiceReceivableId ( receivableId );
                kingInvoiceReceivableDetailEntity.setBatchNum ( batchNumber );
                //计算本位币，税额本位币，价税合计本位币，金额本位币
                kingInvoiceReceivableDetailEntity.setRateAmountCurrency ( CommonUtil.rideStr ( kingInvoiceReceivableDetailEntity.getRateAmount (), rate, 2 ) );
                kingInvoiceReceivableDetailEntity.setTotalTaxPriceCurrency ( CommonUtil.rideStr ( kingInvoiceReceivableDetailEntity.getTotalTaxPrice (), rate, 2 ) );
                kingInvoiceReceivableDetailEntity.setNotTaxAmountCurrency ( CommonUtil.rideStr ( kingInvoiceReceivableDetailEntity.getNotTaxAmount (), rate, 2 ) );
                iKingInvoiceReceivableDetailService.insertKingInvoiceReceivableDetailEntity ( kingInvoiceReceivableDetailEntity );
            } );
        }
    }

    /**
     * 新增应收单收款计划
     * @param kingInvoiceReceivableReceiptPlanEntities
     * @param receivableId
     * @return
     */
    private int updateInvoiceReceiptPlan (List<KingInvoiceReceivableReceiptPlanEntity> kingInvoiceReceivableReceiptPlanEntities, String receivableId) {
        if ( ! CollectionUtils.isEmpty ( kingInvoiceReceivableReceiptPlanEntities ) ) {
            boolean remove = iKingInvoiceReceivableReceiptPlanService.remove ( new LambdaUpdateWrapper<KingInvoiceReceivableReceiptPlanEntity> ().eq ( KingInvoiceReceivableReceiptPlanEntity :: getInvoiceReceivableId, receivableId ) );
            if ( ! remove ) {
                throw new CustomException ( "删除原销售开票计划失败！" );
            }
            kingInvoiceReceivableReceiptPlanEntities.forEach ( kingInvoiceReceivableReceiptPlanEntity -> {
                kingInvoiceReceivableReceiptPlanEntity.setInvoiceReceivableId ( receivableId );
                int i = iKingInvoiceReceivableReceiptPlanService.insertKingInvoiceReceivableReceiptPlanEntity ( kingInvoiceReceivableReceiptPlanEntity );
                if ( i == 0 ) {
                    throw new RuntimeException ( "新增销售开票收款计划失败！" );
                }
            } );
        }
        return 1;
    }

    /**
     * 计算对应源单金额
     * 计算公式：源单(不含税金额/数量)*应收单数量
     * @param receivableEntity
     * @return
     */
    private String calSourceAmount (KingInvoiceReceivableEntity receivableEntity) {
        String sourceAmount = "0";
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_OUT_STORAGE ) {
            KingInventoryMaterialDetailEntity one = iKingInventoryMaterialDetailService.getOne ( new LambdaQueryWrapper<KingInventoryMaterialDetailEntity> ().
                    eq ( KingInventoryMaterialDetailEntity :: getId, receivableEntity.getSourceMaterialDetailId () ) );
            if ( one != null ) {
                sourceAmount = CommonUtil.rideStr ( CommonUtil.divisionStr ( one.getAmountMoney (), one.getReceivedNum (), 2 ), receivableEntity.getDetailNum (), 2 );
            }
        } else if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_REFUND ) {
            KingSaleRefundDetailEntity one = iKingSaleRefundDetailService.getOne ( new LambdaQueryWrapper<KingSaleRefundDetailEntity> ().
                    eq ( KingSaleRefundDetailEntity :: getId, receivableEntity.getSourceMaterialDetailId () ) );
            if ( one != null ) {
                sourceAmount = CommonUtil.rideStr ( CommonUtil.divisionStr ( one.getAmountMoney (), one.getRefundNum (), 2 ), receivableEntity.getDetailNum (), 2 );
            }
        }
        return sourceAmount;
    }

    /**
     * 计算对应源单价税合计，计算公式=源单（价税合计/数量）*应收单数量
     * @param receivableEntity
     * @return
     */
    private String calSourceTaxPriceAmount (KingInvoiceReceivableEntity receivableEntity) {
        //1.获取销售出库单
        String sourceNum = "0", sourceTaxPriceAmount = "0";
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_OUT_STORAGE ) {
            KingInventoryMaterialDetailEntity one = iKingInventoryMaterialDetailService.getOne ( new LambdaQueryWrapper<KingInventoryMaterialDetailEntity> ().
                    eq ( KingInventoryMaterialDetailEntity :: getInventoryMaterialId, receivableEntity.getSourceMaterialDetailId () ) );
            if ( one != null ) {
                sourceNum = one.getReceivedNum ();
                sourceTaxPriceAmount = one.getTotalTaxPrice ();
            }
        } else if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_REFUND ) {
            KingSaleRefundDetailEntity one = iKingSaleRefundDetailService.getOne ( new LambdaQueryWrapper<KingSaleRefundDetailEntity> ().
                    eq ( KingSaleRefundDetailEntity :: getId, receivableEntity.getSourceMaterialDetailId () ) );
            if ( one != null ) {
                sourceNum = one.getRefundNum ();
                sourceTaxPriceAmount = one.getTotalTaxPrice ();
            }
        }
        String result = CommonUtil.rideStr ( CommonUtil.divisionStr ( sourceTaxPriceAmount, sourceNum, 2 ), receivableEntity.getDetailNum (), 2 );
        return result;
    }

    /**
     * 计算源单汇率，直接取源单汇率
     * @param receivableEntity
     * @return
     */
    private String calSourceRate (KingInvoiceReceivableEntity receivableEntity) {
        String sourceRate = "0";
        if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_OUT_STORAGE ) {
            //1.获取销售出库单
            KingInventoryEntity one = iKingInventoryService.getById ( receivableEntity.getDetailSourceId () );
            if ( one != null ) {
                sourceRate = one.getExchangeRate ();
            }
        } else if ( receivableEntity.getSourceDocType () == KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_REFUND ) {
            //2.获取源单为销售退货单
            KingSaleRefundEntity one = iKingSaleRefundService.getOne ( new LambdaQueryWrapper<KingSaleRefundEntity> ().
                    eq ( KingSaleRefundEntity :: getId, receivableEntity.getSourceMaterialDetailId () ) );
            if ( one != null ) {
                if ( one.getDocBusinessType ().equals ( ConstUtil.SALE_REFUND_SOURCE_TYPE_SALE_OUT ) ) {
                    //退货单的源单1，销售出库单
                    KingInventoryEntity inventoryEntity = iKingInventoryService.getOne ( new LambdaQueryWrapper<KingInventoryEntity> ().
                            eq ( KingInventoryEntity :: getId, one.getInventoryId () ) );
                    sourceRate = inventoryEntity.getExchangeRate ();
                } else if ( ConstUtil.SALE_REFUND_SOURCE_TYPE_OTHER_OUT.equals ( one.getDocBusinessType () ) ) {
                    //退货单的源单2，其他出库单

                }
            }
        }
        return sourceRate;
    }


}
